package me.panpf.sketch.util;

import me.panpf.sketch.ImageView;
import me.panpf.sketch.ResourceTable;
import ohos.agp.colors.RgbColor;
import ohos.agp.components.DirectionalLayout;
import ohos.agp.components.Image;
import ohos.agp.components.Text;
import ohos.agp.components.element.Element;
import ohos.agp.components.element.PixelMapElement;
import ohos.agp.components.element.ShapeElement;
import ohos.agp.utils.Color;
import ohos.agp.utils.LayoutAlignment;
import ohos.agp.utils.TextAlignment;
import ohos.agp.window.dialog.ToastDialog;
import ohos.agp.window.service.Display;
import ohos.agp.window.service.DisplayManager;
import ohos.app.Context;
import ohos.global.resource.NotExistException;
import ohos.global.resource.RawFileEntry;
import ohos.global.resource.Resource;
import ohos.global.resource.ResourceManager;
import ohos.hiviewdfx.HiLog;
import ohos.hiviewdfx.HiLogLabel;
import ohos.media.image.ImageSource;
import ohos.media.image.PixelMap;
import ohos.media.image.common.AlphaType;
import ohos.media.image.common.PixelFormat;
import ohos.media.image.common.Rect;
import ohos.media.image.common.Size;

import java.io.ByteArrayOutputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

import static me.panpf.sketch.ImageView.ScaleType.ZOOM_CENTER;

/**
 * Utils
 */
public class Utils {
    private static final String TAG = "sketchok";
    private static HiLogLabel sLogLabel;
    private static final int DOMAIN = 0x001;

    private static HiLogLabel createLogLabel() {
        if (sLogLabel == null) {
            sLogLabel = new HiLogLabel(HiLog.LOG_APP, DOMAIN, TAG);
        }
        return sLogLabel;
    }

    /**
     * info
     *
     * @param format
     * @param objects
     */
    public static void info(String format, Object... objects) {
        HiLog.info(createLogLabel(), format, objects);
    }

    /**
     * debug
     *
     * @param format
     * @param objects
     */
    public static void debug(String format, Object... objects) {
        HiLog.debug(createLogLabel(), format, objects);
    }

    /**
     * error
     *
     * @param format
     * @param objects
     */
    public static void error(String format, Object... objects) {
        HiLog.error(createLogLabel(), format, objects);
    }

    /**
     * warn
     *
     * @param format
     * @param objects
     */
    public static void warn(String format, Object... objects) {
        HiLog.warn(createLogLabel(), format, objects);
    }

    /**
     * fatal
     *
     * @param format
     * @param objects
     */
    public static void fatal(String format, Object... objects) {
        HiLog.fatal(createLogLabel(), format, objects);
    }

    /**
     * 解析准备图片
     *
     * @param context  上下文
     * @param resource 图片资源
     * @return 图片
     * @throws IOException
     * @throws NotExistException
     */
    public static PixelMapElement prepareElement(Context context, Resource resource) throws IOException, NotExistException {
        return new PixelMapElement(preparePixelmap(context, resource));
    }

    /**
     * 解析准备图片
     *
     * @param context  上下文
     * @param resource 图片资源
     * @return 图片
     * @throws IOException
     * @throws FileNotFoundException
     */
    public static PixelMap preparePixelmap(Context context, Resource resource) throws IOException, FileNotFoundException {
        ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions();
        ImageSource imageSource = null;
        try {
            imageSource = ImageSource.create(readResource(resource), srcOpts);
        } finally {
            close(resource);
        }
        if (imageSource == null) {
            throw new FileNotFoundException();
        }
        ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions();
        if (getDisplayWidthInPx(context) < getDisplayHeightInPx(context)) {
            Double aspectRatios = 0.8111533586818758;
            int margin = vp2px(context, context.getString(ResourceTable.String_space_large));
            int width = getDisplayWidthInPx(context) - 2 * margin;
            int height = (int) (width / aspectRatios);
            decodingOpts.desiredSize = new Size(width, height);
        } else {
            decodingOpts.desiredSize = new Size(0, 0);
        }
        decodingOpts.desiredRegion = new Rect(0, 0, 0, 0);
        decodingOpts.desiredPixelFormat = PixelFormat.ARGB_8888;

        PixelMap pixelmap = imageSource.createPixelmap(decodingOpts);
        return pixelmap;
    }

    /**
     * 关闭资源
     *
     * @param resource 资源
     */
    public static void close(Resource resource) {
        if (resource != null) {
            try {
                resource.close();
            } catch (IOException e) {
                Log.error("sketch", e.getMessage());
            }
        }
    }

    /**
     * 读取资源
     *
     * @param resource 资源
     * @return 字节数组
     */
    public static byte[] readResource(Resource resource) {
        final int bufferSize = 1024;
        final int ioEnd = -1;

        ByteArrayOutputStream output = new ByteArrayOutputStream();
        byte[] buffer = new byte[bufferSize];
        while (true) {
            try {
                int readLen = resource.read(buffer, 0, bufferSize);
                if (readLen == ioEnd) {
                    break;
                }
                output.write(buffer, 0, readLen);
            } catch (IOException e) {
                break;
            } finally {
                try {
                    output.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return output.toByteArray();
    }

    /**
     * Creates an empty pixel map
     *
     * @param width  width
     * @param height height
     * @return pixelMap
     */
    public static PixelMap createTransparentPixelMap(int width, int height) {
        PixelMap.InitializationOptions initializationOptions = new PixelMap.InitializationOptions();
        initializationOptions.size = new Size(width, height);
        initializationOptions.alphaType = AlphaType.UNKNOWN;
        initializationOptions.pixelFormat = PixelFormat.ARGB_8888;
        return PixelMap.create(initializationOptions);
    }

    /**
     * 解析尺寸
     *
     * @param dimens 尺寸字符串
     * @return 尺寸值
     */
    public static float parseDimension(String dimens) {
        float dimensFloat = 0f;
        String newDimens = dimens.replace("vp", "").replace("fp", "");
        try {
            dimensFloat = Float.parseFloat(newDimens);
        } catch (NumberFormatException e) {
            e.printStackTrace();
        }
        return dimensFloat;
    }

    /**
     * vp转px
     *
     * @param context 上下文
     * @param dimens  尺寸字符串
     * @return px尺寸值
     */
    public static int vp2px(Context context, String dimens) {
        float vpValue = parseDimension(dimens);
        Display display = DisplayManager.getInstance().getDefaultDisplay(context).get();
        float dpi = display.getAttributes().densityPixels;
        return (int) (vpValue * dpi + 0.5f * (vpValue >= 0 ? 1 : -1));
    }

    /**
     * 获取屏幕宽度
     *
     * @param context 上下文
     * @return 屏幕宽度
     */
    public static int getDisplayWidthInPx(Context context) {
        Display display = DisplayManager.getInstance().getDefaultDisplay(context).get();
        return display.getAttributes().width;
    }

    /**
     * 获取屏幕高度
     *
     * @param context 上下文
     * @return 屏幕高度
     */
    public static int getDisplayHeightInPx(Context context) {
        Display display = DisplayManager.getInstance().getDefaultDisplay(context).get();
        return display.getAttributes().height;
    }

    /**
     * 获取图片资源
     *
     * @param context 上下文
     * @param rawPath 原始文件路径
     * @return 图片资源
     */
    public static ImageSource getImageSource(Context context, String rawPath) {
        ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions();
        ImageSource imageSource = null;
        Resource resource = null;

        ResourceManager resManager = context.getResourceManager();
        RawFileEntry rawFileEntry = resManager.getRawFileEntry(rawPath);
        try {
            resource = rawFileEntry.openRawFile();
            imageSource = ImageSource.create(Utils.readResource(resource), srcOpts);
        } catch (IOException e) {
            Log.error("sketch", e.getMessage());
        } finally {
            close(resource);
        }
        return imageSource;
    }

    /**
     * 获取图片
     *
     * @param context 上下文
     * @param resID   图片资源id
     * @return 图片
     */
    public static PixelMap getPixelMap(Context context, int resID) {
        try {
            Resource resource = context.getResourceManager().getResource(resID);
            PixelMap pixelMap = ImageSource.create(resource, new ImageSource.SourceOptions()).createPixelmap(null);
            return pixelMap;
        } catch (Exception e) {
            Log.error("sketch", e.getMessage());
        }
        return null;
    }

    /**
     * 获取图片
     *
     * @param context 上下文
     * @param rawPath 图片资源路径
     * @return 图片
     */
    public static PixelMap getPixelMap(Context context, String rawPath) {
        ImageSource imageSource = Utils.getImageSource(context, rawPath);
        return imageSource.createPixelmap(null);
    }

    /**
     * 转换缩放模式
     *
     * @param scaleMode 缩放模式
     * @return 缩放模式
     */
    public static ImageView.ScaleType coverScaleMode(Image.ScaleMode scaleMode) {
        ImageView.ScaleType scaleType;
        switch (scaleMode) {
            case ZOOM_CENTER:
                scaleType = ZOOM_CENTER;
                break;
            case ZOOM_START:
                scaleType = ImageView.ScaleType.ZOOM_START;
                break;
            case ZOOM_END:
                scaleType = ImageView.ScaleType.ZOOM_END;
                break;
            case STRETCH:
                scaleType = ImageView.ScaleType.STRETCH;
                break;
            case CENTER:
                scaleType = ImageView.ScaleType.CENTER;
                break;
            case INSIDE:
                scaleType = ImageView.ScaleType.INSIDE;
                break;
            case CLIP_CENTER:
                scaleType = ImageView.ScaleType.CLIP_CENTER;
                break;
            default:
                scaleType = ImageView.ScaleType.STRETCH;
                break;
        }
        return scaleType;
    }

    /**
     * 转换缩放类型
     *
     * @param scaleType 缩放类型
     * @return 缩放模式
     */
    public static Image.ScaleMode coverScaleType(ImageView.ScaleType scaleType) {
        Image.ScaleMode scaleMode;
        switch (scaleType) {
            case ZOOM_CENTER:
                scaleMode = Image.ScaleMode.ZOOM_CENTER;
                break;
            case ZOOM_START:
                scaleMode = Image.ScaleMode.ZOOM_START;
                break;
            case ZOOM_END:
                scaleMode = Image.ScaleMode.ZOOM_END;
                break;
            case STRETCH:
                scaleMode = Image.ScaleMode.STRETCH;
                break;
            case CENTER:
                scaleMode = Image.ScaleMode.CENTER;
                break;
            case INSIDE:
                scaleMode = Image.ScaleMode.INSIDE;
                break;
            case CLIP_CENTER:
                scaleMode = Image.ScaleMode.CLIP_CENTER;
                break;
            case MATRIX:
                scaleMode = Image.ScaleMode.CLIP_CENTER;
                break;
            default:
                scaleMode = Image.ScaleMode.STRETCH;
                break;
        }
        return scaleMode;
    }

    /**
     * 显示toast
     *
     * @param context  上下文
     * @param messenge 显示的文字
     */
    public static void toast(Context context, String messenge) {
        toast(context, messenge, 2000);
    }

    /**
     * 显示toast
     *
     * @param context  上下文
     * @param messenge 显示的文字
     * @param duration 显示持续时间
     */
    public static void toast(Context context, String messenge, int duration) {
        DirectionalLayout toastLayout = new DirectionalLayout(context);
        DirectionalLayout.LayoutConfig toastLayoutConfig =
                new DirectionalLayout.LayoutConfig(DirectionalLayout.LayoutConfig.MATCH_PARENT, DirectionalLayout.LayoutConfig.MATCH_CONTENT);
        toastLayout.setAlignment(LayoutAlignment.BOTTOM | LayoutAlignment.HORIZONTAL_CENTER);
        toastLayout.setLayoutConfig(toastLayoutConfig);

        DirectionalLayout.LayoutConfig textConfig =
                new DirectionalLayout.LayoutConfig(DirectionalLayout.LayoutConfig.MATCH_CONTENT, DirectionalLayout.LayoutConfig.MATCH_CONTENT);
        Text text = new Text(context);
        text.setText(messenge);
        text.setTextColor(new Color(context.getColor(ResourceTable.Color_black)));
        text.setPadding(vp2px(context, "26vp"), vp2px(context, "15vp"), vp2px(context, "26vp"), vp2px(context, "15vp"));
        text.setTextSize(vp2px(context, "13fp"));
        text.setBackground(getElementByColorRadius(Color.getIntColor("#DDFFFFFF"), vp2px(context, "21vp")));
        text.setLayoutConfig(textConfig);
        text.setTextAlignment(TextAlignment.CENTER);
        text.setMultipleLine(true);
        toastLayout.addComponent(text);
        ToastDialog toastDialog = new ToastDialog(context);

        toastLayout.setMarginBottom(200);
        toastDialog.setComponent(toastLayout);
        toastDialog.setSize(DirectionalLayout.LayoutConfig.MATCH_CONTENT, DirectionalLayout.LayoutConfig.MATCH_CONTENT);
        toastDialog.setTransparent(true);
        toastDialog.setDuration(duration);
        toastDialog.show();
    }

    private static Element getElementByColorRadius(int color, float radius) {
        ShapeElement shapeElement = new ShapeElement();
        shapeElement.setShape(0);
        shapeElement.setRgbColor(RgbColor.fromArgbInt(color));
        shapeElement.setCornerRadius(radius);
        return shapeElement;
    }

    /**
     * 获取自适应宽高
     *
     * @param pWidth  图片宽
     * @param pHeight 图片高
     * @param width   控件宽
     * @param height  控件高
     * @return Size 新的大小
     */
    public static Size getPixmapSize(int pWidth, int pHeight, int width, int height) {
        float scaleX = (float) width / pWidth;
        float scaleY = (float) height / pHeight;
        int newWidth = 0;
        int newHeight = 0;
        if (scaleX > scaleY) {
            newWidth = (int) (pWidth * scaleY);
            newHeight = height;
        } else if (scaleX <= scaleY) {
            newWidth = width;
            newHeight = (int) (pHeight * scaleX);
        }
        return new Size(newWidth, newHeight);
    }

}
